/*
 * Copyright 2000 the original author or authors.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "WtSettings.h"
#include "WtContext.h"
#include "WtTable.h"
#include "WtUtil.h"
#include "WtDbSession.h"
#include "WtTableUtil.h"
#include "WtContextEvents.h"

void WtInitOptionCodes(WtContext *w)
{
  Tcl_HashEntry *ent;
  int created;
  Tcl_HashSearch search;
  const char *key;
  int code;
  Tcl_Obj *str;

  if (w->optionCodes) {
    return;
  }

  w->optionCodes = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
  Tcl_InitHashTable(w->optionCodes, TCL_STRING_KEYS);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.reuseInterp", &created);
  Tcl_SetHashValue(ent, WT_SERVER_REUSE_INTERP);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.deleteInterp", &created);
  Tcl_SetHashValue(ent, WT_SERVER_DELETE_INTERP);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.taskNamespace", &created);
  Tcl_SetHashValue(ent, WT_SERVER_TASK_NAMESPACE);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.initInterpScript", &created);
  Tcl_SetHashValue(ent, WT_SERVER_INIT_INTERP_SCRIPT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.loadPackagesScript", &created);
  Tcl_SetHashValue(ent, WT_SERVER_LOAD_PACKAGES_SCRIPT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.startWorkerScript", &created);
  Tcl_SetHashValue(ent, WT_SERVER_START_WORKER_SCRIPT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.createInterpScript", &created);
  Tcl_SetHashValue(ent, WT_SERVER_CREATE_INTERP_SCRIPT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.startRequestSript", &created);
  Tcl_SetHashValue(ent, WT_SERVER_START_REQUEST_SCRIPT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.endRequestSript", &created);
  Tcl_SetHashValue(ent, WT_SERVER_END_REQUEST_SCRIPT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.errorScript", &created);
  Tcl_SetHashValue(ent, WT_SERVER_ERROR_SCRIPT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.restScript", &created);
  Tcl_SetHashValue(ent, WT_SERVER_REST_INTERP_SCRIPT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.deleteInterpScript", &created);
  Tcl_SetHashValue(ent, WT_SERVER_DELETE_INTERP_SCRIPT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.endWorkerScript", &created);
  Tcl_SetHashValue(ent, WT_SERVER_END_WORKER_SCRIPT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.includeStartScript", &created);
  Tcl_SetHashValue(ent, WT_SERVER_INCLUDE_START_SCRIPT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.includeEndScript", &created);
  Tcl_SetHashValue(ent, WT_SERVER_INCLUDE_END_SCRIPT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.includeNamespace", &created);
  Tcl_SetHashValue(ent, WT_SERVER_INCLUDE_NAMESPACE);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.addHeaderTrailer", &created);
  Tcl_SetHashValue(ent, WT_SERVER_ADD_HEADER_TRAILER);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.includeHeader", &created);
  Tcl_SetHashValue(ent, WT_SERVER_INCLUDE_HEADER);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.includeTrailer", &created);
  Tcl_SetHashValue(ent, WT_SERVER_INCLUDE_TRAILER);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.scriptStartString", &created);
  Tcl_SetHashValue(ent, WT_SERVER_SCRIPT_START_STRING);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.scriptEndString", &created);
  Tcl_SetHashValue(ent, WT_SERVER_SCRIPT_END_STRING);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.interpolateText", &created);
  Tcl_SetHashValue(ent, WT_SERVER_INTERPOLATE_TEXT);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.pageTextHandler", &created);
  Tcl_SetHashValue(ent, WT_SERVER_PAGE_TEXT_HANDLER);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.pageExprHandler", &created);
  Tcl_SetHashValue(ent, WT_SERVER_PAGE_EXPR_HANDLER);

  ent = Tcl_CreateHashEntry(w->optionCodes, "session.handler", &created);
  Tcl_SetHashValue(ent, WT_SESSION_HANDLER);

  ent = Tcl_CreateHashEntry(w->optionCodes, "session.handlerType", &created);
  Tcl_SetHashValue(ent, WT_SESSION_HANDLER_TYPE);

  ent = Tcl_CreateHashEntry(w->optionCodes, "session.cookieName", &created);
  Tcl_SetHashValue(ent, WT_SESSION_COOKIE_NAME);

  ent = Tcl_CreateHashEntry(w->optionCodes, "session.maxIdleTime", &created);
  Tcl_SetHashValue(ent, WT_SESSION_MAX_IDLE_TIME);

  ent = Tcl_CreateHashEntry(w->optionCodes, "session.sweepFrequency", &created);
  Tcl_SetHashValue(ent, WT_SESSION_SWEEP_FREQUENCY);

  ent = Tcl_CreateHashEntry(w->optionCodes,
    "session.dbSession.dbHandlerNamespace", &created);
  Tcl_SetHashValue(ent, WT_DB_SESSION_HANDLER);

  ent = Tcl_CreateHashEntry(w->optionCodes, "server.dataSourceHandler", &created);
  Tcl_SetHashValue(ent, WT_DATA_SOURCE_HANDLER);

  /* Get key name from option code */

  w->optionKeys = (Tcl_HashTable *)ckalloc(sizeof(Tcl_HashTable));
  Tcl_InitHashTable(w->optionKeys, TCL_ONE_WORD_KEYS);

  ent = Tcl_FirstHashEntry(w->optionCodes, &search);

  while (ent) {
    key = (const char *)Tcl_GetHashKey(w->optionCodes, ent);
    code = (int)Tcl_GetHashValue(ent);
    Tcl_CreateHashEntry(w->optionKeys, (char *)code, &created);
    str = Tcl_NewStringObj(key, -1);
    Tcl_IncrRefCount(str);
    Tcl_SetHashValue(ent, str);
    ent = Tcl_NextHashEntry(&search);
  }
}

WtOptionCode WtGetOptionCode(const char *key, WtContext *w)
{
  Tcl_HashEntry *ent;

  WtInitOptionCodes(w);

  if (ent = Tcl_FindHashEntry(w->optionCodes, key)) {
    return (WtOptionCode)Tcl_GetHashValue(ent);
  }

  return WT_UNKNOWN_OPTION;
}

Tcl_Obj *WtGetOptionKey(WtOptionCode code, WtContext *w)
{
  Tcl_HashEntry *ent;

  WtInitOptionCodes(w);

  if (ent = Tcl_FindHashEntry(w->optionKeys, (char *)code)) {
    return (Tcl_Obj *)Tcl_GetHashValue(ent);
  }

  return NULL;
}

/* Initialize the default request settings */

int WtInitDefaultContextSettings(WtContext *w)
{
  if (!w->defaultCtxSettings) {
    WtSetObj(&w->defaultCtxSettings, WtNewTableObj());
    WtTableSetStrToStr(w->defaultCtxSettings, "server.dataSourceHandler",
      "::wt::server::dataSources::wtSqlServer");
  }
  return 1;
}

/* Initialize basic web settings */

int WtInitWebSettings(WtContext *w, Tcl_Obj *settings, Tcl_Interp *interp)
{
  int ok = 1;
  Tcl_HashTable *settingsTable = WtGetTableMap(settings);
  Tcl_HashEntry *ent;
  Tcl_HashSearch search;
  const char *key;
  Tcl_Obj *val;

  ent = Tcl_FirstHashEntry(settingsTable, &search);
  while (ent) {
    key = WtToString((Tcl_Obj *)Tcl_GetHashKey(settingsTable, ent));
    val = (Tcl_Obj *)Tcl_GetHashValue(ent);
    if (!WtInitWebSetting(w, key, val, interp)) {
      ok = 0;
      break;
    }
    ent = Tcl_NextHashEntry(&search);
  }

  return ok;
}

/* Init a setting */

int WtInitWebSetting(WtContext *w, const char *key, Tcl_Obj *val,
    Tcl_Interp *interp)
{
  int opt, flag, intVal, ok = 1;
  double dblVal;
  WtDbSession *ds;

  opt = WtGetOptionCode(key, w);

  switch (opt) {
    case WT_SERVER_DELETE_INTERP:
      if (Tcl_GetBooleanFromObj(interp, val, &flag) != TCL_OK) {
        ok = 0;
      } else {
        w->web->deleteInterp = flag;
      }
      break;

    case WT_SERVER_LOAD_PACKAGES_SCRIPT:
      WtTableAppendObjToList(w->web->ctxEventHandlers, "loadPackages", val,
        interp);
      break;

    case WT_SERVER_START_WORKER_SCRIPT:
      WtTableAppendObjToList(w->web->ctxEventHandlers, "startWorker", val,
        interp);
      break;

    case WT_SERVER_CREATE_INTERP_SCRIPT:
      WtTableAppendObjToList(w->web->ctxEventHandlers, "createInterp", val,
        interp);
      break;

    case WT_SERVER_START_REQUEST_SCRIPT:
      WtTableAppendObjToList(w->web->ctxEventHandlers, "startRequest", val,
        interp);
      break;

    case WT_SERVER_END_REQUEST_SCRIPT:
      WtTableAppendObjToList(w->web->ctxEventHandlers, "endRequest", val,
        interp);
      break;

    case WT_SERVER_ERROR_SCRIPT:
      WtTableAppendObjToList(w->web->ctxEventHandlers, "error", val,
        interp);
      break;

    case WT_SERVER_REST_INTERP_SCRIPT:
      WtTableAppendObjToList(w->web->ctxEventHandlers, "restInterp", val,
        interp);
      break;

    case WT_SERVER_DELETE_INTERP_SCRIPT:
      WtTableAppendObjToList(w->web->ctxEventHandlers, "deleteInterp", val,
        interp);
      break;

    case WT_SERVER_END_WORKER_SCRIPT:
      WtTableAppendObjToList(w->web->ctxEventHandlers, "endWorker", val,
        interp);
      break;

    case WT_SERVER_INCLUDE_START_SCRIPT:
      WtTableAppendObjToList(w->web->ctxEventHandlers, "includeStart", val,
        interp);
      break;

    case WT_SERVER_INCLUDE_END_SCRIPT:
      WtTableAppendObjToList(w->web->ctxEventHandlers, "includeEnd", val,
        interp);
      break;

    case WT_SERVER_INCLUDE_NAMESPACE:
      WtSetObj(&w->web->loader.includeNamespace, val);
      break;

    case WT_SERVER_ADD_HEADER_TRAILER:
      if (Tcl_GetBooleanFromObj(interp, val, &flag) != TCL_OK) {
        ok = 0;
      } else {
        w->web->loader.addHeaderTrailer = flag;
      }
      break;

    case WT_SERVER_INCLUDE_HEADER:
      WtSetObj(&w->web->loader.includeHeader, val);
      break;

    case WT_SERVER_INCLUDE_TRAILER:
      WtSetObj(&w->web->loader.includeTrailer, val);
      break;

    case WT_SERVER_SCRIPT_START_STRING:
      WtSetObj(&w->web->loader.scriptStartString, val);
      break;

    case WT_SERVER_SCRIPT_END_STRING:
      WtSetObj(&w->web->loader.scriptEndString, val);
      break;

    case WT_SERVER_INTERPOLATE_TEXT:
      if (Tcl_GetBooleanFromObj(interp, val, &flag) != TCL_OK) {
        ok = 0;
      } else {
        w->web->loader.interpolateText = flag;
      }
      break;

    case WT_SERVER_PAGE_TEXT_HANDLER:
      WtSetObj(&w->web->loader.textHandler, val);
      break;

    case WT_SERVER_PAGE_EXPR_HANDLER:
      WtSetObj(&w->web->loader.exprHandler, val);
      break;

    case WT_SESSION_HANDLER:
      WtSetObj(&w->web->session.handler, val);
      break;

    case WT_SESSION_HANDLER_TYPE:
      WtSetObj(&w->web->session.handlerType, val);
      break;

    case WT_SESSION_COOKIE_NAME:
      WtSetObj(&w->web->session.cookieName, val);
      break;

    case WT_SESSION_MAX_IDLE_TIME:
      if (Tcl_GetIntFromObj(interp, val, &intVal) != TCL_OK) {
        ok = 0;
      } else {
        w->web->session.maxIdleTime = intVal;
      }
      break;

    case WT_SESSION_SWEEP_FREQUENCY:
      if (Tcl_GetDoubleFromObj(interp, val, &dblVal) != TCL_OK) {
        ok = 0;
      } else {
        w->web->session.sweepFrequency = dblVal;
      }
      break;

    case WT_DB_SESSION_HANDLER:
      ds = WtDbSessionRep(w->web->session.dbSession);
      WtSetObj(&ds->dbHandler, val);
      break;

    case WT_DATA_SOURCE_HANDLER:
      WtSetObj(&w->web->dataSourceHandler, val);
      break;
  }

  return ok;
}

int WtDeleteOptionKeys(Tcl_HashTable *optionKeys)
{
  int ok = 1;
  Tcl_HashEntry *ent;
  Tcl_HashSearch search;

  ent = Tcl_FirstHashEntry(optionKeys, &search);
  while (ent) {
    Tcl_DecrRefCount((Tcl_Obj *)Tcl_GetHashValue(ent));
    ent = Tcl_NextHashEntry(&search);
  }

  return ok;
}
